<template>
    <div class="wti-form wti-form2-v2" :class="{ 'border-form': borderForm }">
        <div v-if="showAllFoldBtn || showScanTypeBtn" class="scan-type">
            <!-- 全部收起展开 + 浏览模式切换 -->
            <div v-if="showAllFoldBtn && scanType === 'normal'" class="all-fold-btn" @click="foldAllBlock">
                <svg
                    v-if="!textModel"
                    t="1626835987585"
                    class="all-fold-icon"
                    viewBox="0 0 1024 1024"
                    version="1.1"
                    xmlns="http://www.w3.org/2000/svg"
                    p-id="2264"
                    width="14"
                    height="14"
                >
                    <circle cx="514" cy="514" r="512" stroke="#fff" stroke-width="50" fill="#0062FF" />
                    <path
                        d="M541.184 731.940571V373.76l166.326857 168.374857a29.147429 29.147429 0 1 0 41.179429-41.289143l-237.129143-237.750857-236.068572 236.836572a28.818286 28.818286 0 1 0 39.606858 41.837714l168.740571-167.899429v358.107429a28.708571 28.708571 0 0 0 57.344 0z"
                        fill="#fff"
                    />
                </svg>
                全部{{ allFlod ? '收起' : '展开' }}
            </div>

            <div v-if="showScanTypeBtn && scanType === 'single'" class="block-btn-list">
                <template v-for="block in fields">
                    <div
                        v-if="block.label"
                        :key="block.label"
                        class="block-btn"
                        :class="{ focus: singleScanBlock === block.label }"
                        @click="() => (singleScanBlock = block.label)"
                    >
                        {{ block.label }}
                    </div>
                </template>
            </div>

            <div v-if="showScanTypeBtn" class="scan-type-btn" @click="changeScanType">
                <svg
                    t="1626835987585"
                    class="scan-type-icon"
                    viewBox="0 0 28 28"
                    version="1.1"
                    xmlns="http://www.w3.org/2000/svg"
                    p-id="2264"
                    width="14"
                    height="14"
                >
                    <path d="M2 6 L9 2 L9 10 Z L25 6" stroke="#12182A" fill="#12182A" />
                    <path d="M26 22 L19 18 L19 26 Z L2 22" stroke="#12182A" fill="#12182A" />
                </svg>
                浏览模式切换
            </div>
        </div>

        <el-form
            ref="form"
            v-bind="$attrs"
            :model="formData"
            :hide-required-asterisk="textModel"
            :label-width="labelWidth || '150px'"
            :label-position="labelPosition ? labelPosition : 'top'"
        >
            <!-- 区块级，每个 filed 是一个区块 -->
            <div v-for="field in currentFileds" :key="field.label">
                <div
                    v-if="scanType === 'normal' || (scanType === 'single' && singleScanBlock === field.label)"
                    :class="getBlockClass(field)"
                    :style="field.style"
                >
                    <!-- 区块名 -->
                    <div v-if="field.label" class="form-title">
                        <div class="text">
                            <span class="dec" />
                            <span :id="field.id || String(Math.random() * 10000)" class="title-name">
                                {{ field.label }}
                            </span>
                            <div
                                v-if="showFoldBtn && !textModel && scanType === 'normal'"
                                class="collapse"
                                @click="foldBlock(field)"
                            >
                                <i
                                    class="el-icon-d-arrow-right"
                                    :class="{ 'arrow-top': foldBlockList.indexOf(field.label) > -1 }"
                                />
                            </div>
                            <slot name="button" />
                        </div>
                        <span v-if="field.required" class="tips">为必填项</span>
                    </div>

                    <template v-for="(row, rowIndex) in getFieldRow(field.children)">
                        <el-row
                            :key="rowIndex"
                            :gutter="20"
                            class="block-content"
                            :class="{
                                'block-hidden': foldBlockList.indexOf(field.label) > -1
                            }"
                        >
                            <template v-for="{ rowItem } in row">
                                <div :key="rowItem.key">
                                    <el-col :key="rowItem.key" :span="getColSize(rowItem)" :style="rowItem.style || {}">
                                        <ChildForm
                                            v-if="rowItem.type === 'child-form'"
                                            :ref="rowItem.key"
                                            v-model.trim="formData[rowItem.key]"
                                            :text-model="textModel"
                                            :all-disabled="allDisabled"
                                            :label-position="labelPosition ? labelPosition : 'top'"
                                            :item="rowItem"
                                        />

                                        <TableReadonly
                                            v-else-if="rowItem.type === 'table-readonly'"
                                            :ref="rowItem.key"
                                            v-model="formData[rowItem.key]"
                                            :item="rowItem"
                                        />
                                        <div v-else-if="rowItem.type === 'slot-single'">
                                            <slot :name="rowItem.name" />
                                        </div>
                                        <el-form-item
                                            v-else-if="rowItem.type === 'slot'"
                                            :style="rowItem.style"
                                            :class="rowItem.class"
                                            :label="getFormItemLabel(rowItem)"
                                        >
                                            <!-- eslint-disable-next-line -->
                                            <div v-if="rowItem.htmlLabel" slot="label" v-html="rowItem.htmlLabel"></div>
                                            <slot :name="rowItem.name" />
                                        </el-form-item>
                                        <el-form-item
                                            v-else
                                            :style="rowItem.style"
                                            :class="[rowItem.required ? 'is-required' : '', rowItem.class]"
                                            :rules="getItemRules(rowItem.type, rowItem.rules)"
                                            :label="getFormItemLabel(rowItem)"
                                            :prop="rowItem.key"
                                            :label-width="rowItem['label-width']"
                                        >
                                            <!-- 自定义label插槽 -->
                                            <span v-if="rowItem.labelSlot" slot="label" v-html="rowItem.labelSlot"></span>
                                            <component
                                                :is="getCurrentComponent(rowItem.type)"
                                                v-model="formData[rowItem.key]"
                                                v-bind="getProps(rowItem)"
                                            />
                                        </el-form-item>
                                    </el-col>
                                </div>
                            </template>
                        </el-row>
                    </template>
                    <el-divider v-if="field.divider" />
                </div>
            </div>
            <!-- 表头加粗文字开始 -->
        </el-form>
    </div>
</template>

<script>
// import axios from 'axios';
import FormInput from './components/FormInput'
import FormTextarea from './components/FormTextarea'
import FormDynamicSelect from './components/FormDynamicSelect'
import FormNormalSelect from './components/FormNormalSelect'
import FormDateInput from './components/FormDateInput'
import FormHourMinuteInput from './components/FormHourMinuteInput'
import FormDateRangeInput from './components/FormDateRangeInput'
import FormAutoCompleteInput from './components/FormAutoCompleteInput'
import FormNumberInput from './components/FormNumberInput'
import FormRadio from './components/FormRadio'
import FormMoneyInput from './components/FormMoneyInput'
import FormRateInput from './components/FormRateInput'
import FormAreaSelect from './components/FormAreaSelect'
import FormMulLinkage from './components/FormMulLinkage'
import FormNormalNumber from './components/FormNormalNumber'
import FormMulSelectNormal from './components/FormMulSelectNormal'
import FormStake from './components/FormStake'

import TableReadonly from './components/TableReadonly'

import ChildForm from './ChildForm'
import FormMixin from './mixin'

export default {
    name: 'BaseForm2',
    components: {
        FormInput,
        FormDynamicSelect,
        FormDateInput,
        FormHourMinuteInput,
        FormDateRangeInput,
        FormNumberInput,
        FormAutoCompleteInput,
        FormRadio,
        FormTextarea,
        FormNormalSelect,
        FormMoneyInput,
        FormRateInput,
        FormAreaSelect,
        FormMulLinkage,
        FormNormalNumber,
        FormMulSelectNormal,
        FormStake,
        TableReadonly,
        ChildForm
    },
    mixins: [FormMixin],
    props: {
        fields: {
            type: Array,
            default: () => []
        },
        data: {
            type: Object,
            default: () => ({})
        },
        // 是否显示收起、展开按钮
        showFoldBtn: {
            type: Boolean,
            default: false
        },
        // 是否显示 全部收起、展开按钮
        showAllFoldBtn: {
            type: Boolean,
            default: false
        },
        // 是否显示浏览模式切换按钮
        showScanTypeBtn: {
            type: Boolean,
            default: false
        }
    },
    data() {
        // 桩号是个数组结构，进行特殊验证
        const validateStake = (rule, value, callback) => {
            value.forEach((item, index) => {
                if (!item && item !== null) {
                    callback(new Error('必填项'))
                } else {
                    if (index === 1) {
                        if (item === null || item.length !== 3) {
                            callback(new Error('格式错误'))
                        } else {
                            callback()
                        }
                    }
                }
            })
        }
        return {
            formData: {},

            currentFileds: [], // 中间态数据，依赖于 fields。当 fields 改变时，这个会跟着一起变。

            // 动态下拉列表里，所有选项。本对象的属性 key 是字典的父 key，值是数组，数组元素是对应的父 key 下所有字典
            dynamicDict: {},

            changeData: {
                // 所有动态数据，更准确的说，是会重新赋值的，需要放到 data 里，才能实现响应式。这是因为 provide 本身的特性导致的
                // 被禁用的所有元素列表。这里的数组元素是该要素的 key。
                disableList: [],
                allDisabled: this.allDisabled,

                // 隐藏的要素列表。这里的数组元素是该要素的 key。
                // 隐藏的要素，不进行校验。提交的时候，也要过滤掉
                hiddenKeyList: [],
                textModel: this.textModel
            },

            foldBlockList: [], // 收起的区块（放在这个里面，该区块就只显示区块标题，不显示内容）

            scanType: 'normal', // normal 默认（大表单），single（表单只显示单个区块，上方显示所有区块的按钮组）
            singleScanBlock: '', // 单个模式时，显示哪个表单
            foldStatus: false,
            stakeRules: [
                // { required: true, trigger: 'blur', message: '必填项1' },
                { validator: validateStake, trigger: ['blur'] }
            ]
        }
    },
    computed: {
        allFlod() {
            const labelList = []
            this.fields.forEach(block => {
                // 如果没有 label，则不支持收起
                block.label && labelList.push(block.label)
            })
            return this.foldBlockList.length !== labelList.length
        }
    },
    watch: {
        textModel(n) {
            this.$set(this.changeData, 'textModel', n)
        }
    },
    created() {
        this.currentFileds = this.fields

        this.initFormData()
        // 加载初始情况下，默认禁用的要素
        this.getDefaultDisableList()
        // 默认隐藏
        this.getDefaultHiddenList()
        // 动态加载需要数据字典的选项
        this.loadDynamicSelectOptions()
        this.initStatus()

        // 理论上，不应该动态添加 fileds。尽量 fields 通过事件，内部控制自己是否显示
        this.$watch('fields', v => {
            this.currentFileds = []
            this.$nextTick(() => {
                this.currentFileds = v
                this.getDefaultDisableList()
                this.getDefaultHiddenList()
                this.loadDynamicSelectOptions()
                this.initFormData()
                this.initStatus()
            })
        })

        this.$watch('data', () => {
            this.initFormData()
            this.initStatus()
        })
    },
    provide() {
        return {
            dynamicSelectOption: this.dynamicSelectOption,
            dynamicDict: this.dynamicDict,
            // 状态切换函数
            statusChangeFn: {
                // 设置为禁用
                setElementDisable: this.setElementDisable,
                // 设置为隐藏
                setElementHidden: this.setElementHidden,
                // 设置为必填
                setElementRequired: this.setElementRequired,
                // 更新其他数据
                updateFormData: this.updateFormData,
                valueUpdateEvent: this.valueUpdateEvent
            },
            // 会动态变化的数据（注意，来自 props【更上级组件】的数据，不能放这个里面，只能显式的通过 props 往下面传）
            changeData: this.changeData,
            formItemType: '',
            childChangeData: {}
        }
    },
    methods: {
        getItemRules(type, rules) {
            console.log(964)
            if (type === 'stake') {
                if (rules) {
                    console.log(rules)
                    return rules
                }
                return this.stakeRules
            } else {
                return rules
            }
        },
        // 把类型type转为对应的大驼峰形式，与组件名对应
        getCurrentComponent(type) {
            const arr = type.split('-')
            let result = 'Form'
            arr.forEach(item => {
                item = item.substring(0, 1).toUpperCase() + item.substring(1, item.length)
                result += item
            })
            return result
        },
        // 监听值更新
        valueUpdateEvent(params) {
            this.$emit('updateValue', params)
        },

        // 初始化 formData 的值
        initFormData() {
            this.$set(this, 'formData', {})
            // console.log('initFormData');
            // 用 fileds 初始化 formData 的 key
            this.fields.forEach(fields => {
                if (fields.children && fields.children instanceof Array) {
                    fields.children.forEach(field => {
                        // 处理初始值的问题
                        // 1. 如果是插槽，那么直接忽略这个
                        if (field.type === 'slot') {
                            return
                        }

                        // 2. 如果该值在 data 里，则直接取 data 里的值（面对场景：数值回显）
                        if (field.key in this.data) {
                            this.$set(this.formData, field.key, this.data[field.key])
                            // 赋值默认值的时候，触发事件通知上级
                            this.valueUpdateEvent({
                                [field.key]: this.data[field.key]
                            })
                        } else {
                            // 3. 不需要回显的场景下
                            // 3.1 如果该要素有默认值，则使用默认值
                            if (field.defaultValue) {
                                this.$set(this.formData, field.key, field.defaultValue)
                                // 赋值默认值的时候，触发事件通知上级
                                this.valueUpdateEvent({
                                    [field.key]: field.defaultValue
                                })
                            } else {
                                // 3.2 该要素没有默认值，使用通用默认值
                                const types = ['child-form', 'table-readonly', 'mul-linkage', 'mul-select-normal']
                                if (types.includes(field.type)) {
                                    this.$set(this.formData, field.key, [])
                                } else if (field.type === 'area-select') {
                                    this.$set(this.formData, field.key, ['', '', ''])
                                } else {
                                    this.$set(this.formData, field.key, '')
                                }
                            }
                        }
                    })
                }
            })
        },

        // 获取初始情况下，所有默认禁用要素
        getDefaultDisableList() {
            const disableList = []
            // 遍历传入的数据
            this.fields.forEach(fields => {
                if (fields.children && fields.children instanceof Array) {
                    fields.children.forEach(field => {
                        // 如果是true，则添加到禁用列表里
                        field.disableDefault && disableList.push(field.key)
                    })
                }
            })

            this.changeData.disableList = disableList
        },

        // 默认隐藏
        getDefaultHiddenList() {
            const hiddenList = []
            // 遍历传入的数据
            this.fields.forEach(fields => {
                if (fields.children && fields.children instanceof Array) {
                    fields.children.forEach(field => {
                        // 如果是true，则添加到禁用列表里
                        field.hiddenDefault && hiddenList.push(field.key)
                    })
                }
            })

            this.changeData.hiddenKeyList = hiddenList
        },

        // 对一个 block 下的要素，进行 el-row 的分行
        getFieldRow(children) {
            // 一个二维数组，每个数组要素是 el-row 的一行
            const list = []
            if (!children) {
                return list
            }
            children.forEach(item => {
                // 如果当前要素不显示，则直接跳过
                if (!this.isShow(item)) {
                    return
                }
                const currentSpan = this.getColSize(item)
                // 如果初始为空
                if (list.length === 0) {
                    const obj = {
                        // 获取到他有多少 span，满 24 为一行
                        span: currentSpan,
                        rowItem: item
                    }
                    list.push([obj])
                    return
                }
                // 如果初始不为空，
                // 1、判断有没有打开 （当前这个的）【默认在新行第一列】开关
                // 又或者是当前是不是子表单（item.type === 'child-form'表示是子表单）
                if (item.nextRowFirst || item.type === 'child-form' || item.type === 'table-readonly') {
                    // 如果是新行第一列，那么直接把这个添加到 list 里面
                    const obj = {
                        // 获取到他有多少 span，满 24 为一行
                        span: currentSpan,
                        rowItem: item
                    }
                    list.push([obj])
                    return
                }
                // 2、判断（上一个）【默认是本行最后一列】开关是否打开
                // 先拿到最后一行
                const listLastItem = list[list.length - 1]
                // 的最后一个是否打开了这个开关
                if (listLastItem[listLastItem.length - 1].rowItem.currentRowLast) {
                    // 如果打开这个开关，那么当前这个直接放到下一行的第一个
                    const obj = {
                        // 获取到他有多少 span，满 24 为一行
                        span: currentSpan,
                        rowItem: item
                    }
                    list.push([obj])
                    return
                }

                // 下拉正常计算 span 来决定是否换行
                // 那么计算 list 最后一个数组里面所有加起来的 span 的值
                const lastTotalSpan = list[list.length - 1]
                    .map(item => item.span)
                    .reduce((lastTotal, currentItem) => {
                        return lastTotal + currentItem
                    })

                // 如果已经大于等于 24 了，说明满了一行，那么直接创建新行
                // 或者是当前这个加之前的大于 24，那么说明这个放在之前那行超过 24，所以也要放到新行去
                if (lastTotalSpan >= 24 || lastTotalSpan + currentSpan > 24) {
                    const obj = {
                        // 获取到他有多少 span，满 24 为一行
                        span: currentSpan,
                        rowItem: item
                    }
                    list.push([obj])
                } else {
                    // 此时说明当前这个可以放到之前哪一行
                    const obj = {
                        // 获取到他有多少 span，满 24 为一行
                        span: currentSpan,
                        rowItem: item
                    }
                    list[list.length - 1].push(obj)
                }
            })
            return list
        },

        // 设置某个要素禁用
        // key：操作的 key
        // beDisable：必填，默认是 true，表示禁用。而 false，表示取消禁用
        setElementDisable(key, beDisable = true) {
            // 设置禁用
            if (beDisable) {
                // 已经禁用了，则跳过。否则则添加进去
                if (this.changeData.disableList.indexOf(key) === -1) {
                    this.changeData.disableList.push(key)
                }
            } else {
                // 取消禁用
                // 未禁用则跳过。已经禁用，则继续
                const index = this.changeData.disableList.indexOf(key)
                if (index > -1) {
                    this.changeData.disableList = [
                        ...this.changeData.disableList.slice(0, index),
                        ...this.changeData.disableList.slice(index + 1)
                    ]
                }
            }
        },

        // 设置某个要素隐藏
        // key：操作的 key
        // beHidden：必填，默认是 true，表示隐藏。而 false，表示取消隐藏
        setElementHidden(key, beHidden = true) {
            // 设置隐藏
            if (beHidden) {
                // 已经禁用了，则跳过。否则则添加进去
                if (this.changeData.hiddenKeyList.indexOf(key) === -1) {
                    this.changeData.hiddenKeyList.push(key)
                }
            } else {
                // 取消禁用
                // 未禁用则跳过。已经禁用，则继续
                const index = this.changeData.hiddenKeyList.indexOf(key)
                if (index > -1) {
                    this.changeData.hiddenKeyList = [
                        ...this.changeData.hiddenKeyList.slice(0, index),
                        ...this.changeData.hiddenKeyList.slice(index + 1)
                    ]
                }
            }
        },

        // 设置某个要素必填
        // key：操作的 key
        // beHidden：必填，默认是 true，表示隐藏。而 false，表示取消隐藏
        setElementRequired(key, beRequired = true) {
            // 设置必填
            if (beRequired) {
                // 先找到这个要素，如果其本身必填，则跳过。
                // 遍历传入的数据
                this.fields.forEach(fields => {
                    if (fields.children && fields.children instanceof Array) {
                        fields.children.forEach(field => {
                            // 如果 key 不匹配，则跳过
                            if (field.key !== key) {
                                return
                            }
                            // 先判断有没有 rules 这个属性，没有则添加这个属性，并且添加必填项然后返回
                            if (!field.rules) {
                                this.$set(field, 'rules', [
                                    {
                                        required: true,
                                        message: '请输入',
                                        trigger: ['blur', 'change']
                                    }
                                ])
                                return
                            }

                            // 遍历 其 rules，
                            const { rules } = field
                            // 是否有 required 这条规则
                            let haveRequired = false
                            // 是否已修改
                            let changed = false
                            rules.forEach(rule => {
                                // 如果有 required 属性
                                if ('required' in rule) {
                                    haveRequired = true
                                    // 如果值为 true，则跳过
                                    if (rule.required) {
                                        //
                                    } else {
                                        // 否则修改其为 true
                                        rule.required = true
                                        changed = true
                                    }
                                }
                            })
                            // 如果已修改，那么说明没必要继续操作了，跳过
                            if (changed) {
                                return
                            }
                            // 如果没修改，并且没有必填规则
                            // （注意，如果有规则，那么必然已修改。所以只存在有规则已修改、未修改有规则、未修改无规则三种情况）
                            if (!haveRequired) {
                                // 添加规则
                                rules.push({
                                    required: true,
                                    message: '请输入',
                                    trigger: ['blur', 'change']
                                })
                            }
                        })
                    }
                })
            } else {
                // 取消必填
                // 不含必填规则的话，则跳过。如果含必填规则，则添加
                this.fields.forEach(fields => {
                    if (fields.children && fields.children instanceof Array) {
                        fields.children.forEach(field => {
                            // 如果 key 不匹配，则跳过
                            if (field.key !== key) {
                                return
                            }

                            // 先判断有没有 rules 这个属性，没有则添加这个属性，并且添加必填项然后返回
                            if (!field.rules) {
                                return
                            }
                            // 如果有，则遍历并删除
                            let i = -1
                            field.rules.forEach((rule, index) => {
                                if ('required' in rule) {
                                    i = index
                                }
                            })
                            if (i !== -1) {
                                field.rules.splice(i, 1)
                            }
                        })
                    }
                })
            }
        },

        // 初始化要素的 隐藏/显示、禁用/非禁用 状态等
        // 在父组件 data 更新的时候，调用这个方法
        initStatus() {
            // 遍历传入的数据
            this.fields.forEach(fields => {
                if (fields.children && fields.children instanceof Array) {
                    fields.children.forEach(field => {
                        // 如果有联动项，那么则遍历每个联动项
                        if (field.valueLink && field.valueLink.length && field.valueLink.length > 0) {
                            const { key } = field
                            const v = this.data[key]
                            // 遍历
                            field.valueLink.forEach(linkItem => {
                                // 如果联动项的触发值不匹配，则跳过这一条
                                if (v !== linkItem.value) {
                                    return
                                }
                                // 此时匹配，判断 linkList 有没有
                                if (linkItem.linkList && linkItem.linkList.length && linkItem.linkList.length > 0) {
                                    // 再遍历
                                    linkItem.linkList.forEach(triggerItem => {
                                        const linkKey = triggerItem.linkKey
                                        // 如果没有联动 key，则跳过（正常来说，不会没有）
                                        if (!linkKey) {
                                            return
                                        }
                                        // 如果联动值，则更新值
                                        if (triggerItem.enableLinkValue) {
                                            this.updateFormData({ [linkKey]: triggerItem.linkValue })
                                        }
                                        // 如果联动禁用/取消禁用，则更新禁用
                                        if (triggerItem.enableLinkDisable) {
                                            this.setElementDisable(linkKey, triggerItem.linkDisable)
                                        }
                                        // 如果联动隐藏/显示，则更新
                                        if (triggerItem.enableLinkHidden) {
                                            this.setElementHidden(linkKey, triggerItem.linkHidden)
                                        }
                                        // 如果联动必填/非必填，则更新
                                        if (triggerItem.enableLinkRequired) {
                                            this.setElementRequired(linkKey, triggerItem.linkRequired)
                                        }
                                    })
                                }
                            })
                        }
                    })
                }
            })
        },

        // 找到 type="dynamic-select" 获取所有 parentCode，然后读取数据字典接口拉取对应的数据
        // todo 这里的数据字典请求接口，应该最后合并到一起，由一个专门的数据字典请求管理器去请求，减低接口重复请求的情况
        loadDynamicSelectOptions() {
            const parentCodeList = []
            // 遍历传入的数据
            this.fields.forEach(fields => {
                if (fields.children && fields.children instanceof Array) {
                    fields.children.forEach(field => {
                        if (field.type === 'dynamic-select' && field.parentKey) {
                            // 再做一次去重判断。如果该字典已经在里面了，再跳过这一个
                            if (parentCodeList.indexOf(field.parentKey) === -1) {
                                if (
                                    !(
                                        this.dynamicDict[field.parentKey] &&
                                        this.dynamicDict[field.parentKey].length !== 0
                                    )
                                ) {
                                    parentCodeList.push(field.parentKey)
                                    // 初始化一个数组
                                    this.$set(this.dynamicDict, field.parentKey, [])
                                }
                            }
                        }
                        // 地区选择框，三级联动
                        // if (field.type === 'area-select') {
                        //     const firstParentKey = field.firstParentKey || '10020'
                        //     const secondParentKey = field.firstParentKey || '10021'
                        //     const thirdParentKey = field.firstParentKey || '10022'
                        //     if (parentCodeList.indexOf(firstParentKey) === -1) {
                        //         if (!(this.dynamicDict[firstParentKey] && this.dynamicDict[firstParentKey].length !== 0)) {
                        //             parentCodeList.push(firstParentKey)
                        //             this.$set(this.dynamicDict, firstParentKey, [])
                        //         }
                        //     }
                        //     if (parentCodeList.indexOf(secondParentKey) === -1) {
                        //         if (!(this.dynamicDict[secondParentKey] && this.dynamicDict[secondParentKey].length !== 0)) {
                        //             parentCodeList.push(secondParentKey)
                        //             this.$set(this.dynamicDict, secondParentKey, [])
                        //         }
                        //     }
                        //     if (parentCodeList.indexOf(thirdParentKey) === -1) {
                        //         if (!(this.dynamicDict[thirdParentKey] && this.dynamicDict[thirdParentKey].length !== 0)) {
                        //             parentCodeList.push(thirdParentKey)
                        //             this.$set(this.dynamicDict, thirdParentKey, [])
                        //         }
                        //     }
                        // }
                    })
                }
            })
            if (parentCodeList.length === 0) {
                return
            }
            parentCodeList.forEach(code => {
                this.dynamicSelectOption.model[this.dynamicSelectOption.apiName](code)
                    .then(res => {
                        this.dynamicDict[code] = res || []
                    })
                    .catch(() => {
                        this.$message.error('数据字典加载错误！')
                    })
            })
        },

        // 清空校验信息
        clearValidate() {
            this.$refs.form.clearValidate()
        },

        // 获取过滤后的数据
        getData() {
            const d = {}
            Object.keys(this.formData)
                .filter(key => {
                    // 走正常逻辑
                    if (this.changeData.hiddenKeyList.indexOf(key) > -1) {
                        return false
                    } else {
                        return true
                    }
                })
                .forEach(key => {
                    // 这里分为两种情况：
                    // 第一种是一级表单的元素，他在被隐藏时，key是可以直接从 hiddenKeyList 获取的
                    // 第二种是子表单的元素。因为他的 key 是三段拼接起来的 key，所以要去子表单里拿到 randomId 再做一个映射
                    // 某个属性是否是子表单的判断条件是：遍历 fields，判断他是否是 type === 'child-form'
                    let childFormKeysList = []
                    this.fields
                        .map(field => {
                            const list = []
                            field.children.forEach(item => {
                                if (item.type === 'child-form') {
                                    list.push(item.key)
                                }
                            })
                            return list
                        })
                        .filter(list => {
                            return list.length > 0
                        })
                        .forEach(list => {
                            childFormKeysList = [...childFormKeysList, ...list]
                        })
                    if (childFormKeysList.indexOf(key) > -1) {
                        // 说明是在子表单
                        d[key] = this.$refs[key][0].childFormFileds.map((childField, index) => {
                            const childD = {}
                            const { randomId } = childField
                            childField.forEach(childItem => {
                                const childKey = childItem.key
                                const keyText = `${key}_${randomId}_${childKey}`
                                if (this.changeData.hiddenKeyList.indexOf(keyText) > -1) {
                                    //
                                } else {
                                    childD[childKey] = this.formData[key][index][childKey]
                                }
                            })
                            return childD
                        })
                    } else {
                        // 走正常逻辑
                        d[key] = this.formData[key]
                    }
                })
            return d
        },

        // 校验，并获取校验后数据
        validate(fn) {
            // 先校验父级表单的值
            this.$refs.form.validate(valid => {
                // 对数据进行过滤
                const data = this.getData()

                // 判断是否需要校验子表单
                const childFormKeyList = []
                this.fields.forEach(filed => {
                    if (filed.children && filed.children.length > 0) {
                        filed.children.forEach(formItem => {
                            // 如果某一项是
                            if (formItem.type === 'child-form') {
                                childFormKeyList.push(formItem.key)
                            }
                        })
                    }
                })

                if (childFormKeyList.length === 0) {
                    if (valid) {
                        fn(true, data)
                    } else {
                        fn(false, data)
                    }
                } else {
                    const validateList = childFormKeyList.map(key => {
                        return this.$refs[key][0].validateForm()
                    })
                    Promise.all(validateList)
                        .then(() => {
                            // 父表单校验也通过了，才算都通过
                            if (valid) {
                                fn(true, data)
                            } else {
                                // 否则即使子表单校验通过，父表单校验没通过，也是算不通过的
                                fn(false, data)
                            }
                        })
                        .catch(() => {
                            fn(false, data)
                        })
                }
            })
        },

        // 重置表单数据
        resetFields() {
            this.$refs.form.resetFields()
            this.fields.forEach(filed => {
                if (filed.children && filed.children.length > 0) {
                    filed.children.forEach(formItem => {
                        // 如果某一项是
                        if (formItem.type === 'child-form') {
                            const a = this.$refs[formItem.key]
                            if (a instanceof Array) {
                                a[0].resetFields()
                            } else {
                                a.resetFields()
                            }
                        }
                    })
                }
            })
        },

        // 表单组件是否显示
        isShow(item) {
            // 如果该要素在隐藏列表里，则不显示
            if (this.changeData.hiddenKeyList.indexOf(item.key) > -1) {
                return false
            }
            return true
        },

        // 更新数据
        updateFormData(data) {
            Object.keys(data).forEach(key => {
                // 如果 key 在值里面
                if (key in this.formData) {
                    // 则回填这个值
                    this.$set(this.formData, key, data[key])
                }
            })
        },

        // 收起/展开区块
        foldBlock(block) {
            this.foldStatus = !this.foldStatus
            const label = block.label
            const index = this.foldBlockList.indexOf(label)
            if (index === -1) {
                this.foldBlockList.push(block.label)
            } else {
                this.foldBlockList.splice(index, 1)
            }
        },

        // 收起展开所有区块
        foldAllBlock() {
            const labelList = []
            this.fields.forEach(block => {
                // 如果没有 label，则不支持收起
                if (block.label) {
                    labelList.push(block.label)
                }
            })
            // 如果长度相等，说明已经全部收起了，那么就是展开
            if (this.foldBlockList.length === labelList.length) {
                this.foldBlockList = []
            } else {
                this.foldBlockList = labelList
            }
        },

        // 浏览模式切换
        changeScanType() {
            if (this.scanType === 'normal') {
                this.scanType = 'single'
                // 如果切换为单体，那么将所有隐藏的显示出来
                this.foldBlockList = []
                this.singleScanBlock = this.fields[0].label
            } else {
                this.scanType = 'normal'
                this.singleScanBlock = ''
            }
        },

        getProps(rowItem) {
            return {
                ref: rowItem.key,
                item: rowItem,
                allDisabled: this.allDisabled
            }
        }
    }
}
</script>

<style scoped lang="scss">
.wti-form {
    width: 100%;
    .block-title {
        position: relative;
        height: 50px;
        padding-top: 10px;
        padding-bottom: 24px;
        font-size: 16px;

        // label 左边的红色竖线
        .block-line {
            float: left;
            width: 4px;
            height: 16px;
            background: #ee473a;
            border-radius: 2px;
        }

        .block-text {
            margin-left: 10px;
            float: left;
            height: 16px;
            font-size: 16px;
            color: #21273a;
            font-weight: 600 !important;
            vertical-align: top;
            line-height: 16px;
        }

        .block-fold-btn {
            float: right;
            margin-right: 30px;
            height: 16px;
            line-height: 16px;
            font-size: 14px;
            cursor: pointer;
            user-select: none;
        }
    }
}
// 带边框的表单组件
.border-form {
    .block-item {
        // border: 1px solid #dde0ea;
        border-radius: 8px;
        background: #fff;

        .block-title {
            height: 60px;
            line-height: 60px;
            background: #f8f9fb;
            padding: 20px 0 18px 24px;
            border-top-left-radius: 8px;
            border-top-right-radius: 8px;
            margin-bottom: 18px;
            border-bottom: 1px solid #dde0ea;
        }

        // .block-title + .block-content {
        //   padding-top: 14px;
        // }

        .block-content {
            padding: 0 24px;
        }

        .block-hidden {
            display: none;
        }
    }
    .block-item+.block-item {
        margin-bottom: 40px;
        padding-bottom: 15px;
    }

    .block-hide {
        padding-bottom: 0;

        .block-title {
            border-bottom: 0;
            overflow: hidden;
            border-radius: 8px;
            margin-bottom: 0;
        }
    }
}

.el-divider {
    background-color: #f4f5f8;
}

.scan-type {
    position: relative;
    height: 36px;
    line-height: 36px;
    margin-bottom: 16px;

    .all-fold-btn {
        display: inline-block;
        padding: 0 20px;
        height: 36px;
        background: #0062ff;
        border: 1px solid #0062ff;
        border-radius: 4px;
        color: #fff;
        cursor: pointer;
        text-align: center;
        font-size: 14px;
        vertical-align: top;

        .all-fold-icon {
            width: 14px;
            height: 14px;
            vertical-align: top;
            margin-top: 11px;
        }
    }

    .block-btn-list {
        float: left;
        height: 36px;

        .block-btn {
            border: 1px solid #dde0ea;
            height: 36px;
            line-height: 34px;
            padding: 0 18px;
            color: #3a4566;
            display: inline-block;
            cursor: pointer;
            user-select: none;
        }

        .block-btn.focus {
            background: #ee473a;
            color: #fff;
        }

        .block-btn:first-child {
            border-radius: 4px 0 0 4px;
        }

        .block-btn:last-child {
            border-radius: 0 4px 4px 0;
        }
    }

    .scan-type-btn {
        float: right;
        padding: 0 20px;
        height: 36px;
        border: 1px solid #aeb3bf;
        border-radius: 4px;
        color: #12182a;
        cursor: pointer;
        text-align: center;
        font-size: 14px;
        vertical-align: top;
        user-select: none;

        .scan-type-icon {
            width: 14px;
            height: 14px;
            vertical-align: top;
            margin-top: 11px;
        }
    }
}

.wti-form2-v2 ::v-deep input::-webkit-outer-spin-button,
.wti-form2-v2 ::v-deep input::-webkit-inner-spin-button {
    -webkit-appearance: none;
}

.wti-form2-v2 ::v-deep input[type='number'] {
    -webkit-appearance: none;
    appearance: none;
}

.wti-form2-v2 ::v-deep input[type='number'] {
    -moz-appearance: textfield;
}

.form-title {
    width: 100%;
    height: 20px;
    margin-bottom: 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-size: 14px;
    color: #171725;
    .collapse {
        font-weight: bold;
        padding: 0 24px;
        cursor: pointer;
        .el-icon-d-arrow-right {
            transition: 0.3s;
            transform: rotate(90deg);
        }
        .arrow-top {
            transform: rotate(-90deg);
        }
    }
    .text {
        display: flex;
        align-items: center;
        .dec {
            display: inline-block;
            width: 2px;
            height: 1em;
            background: #0062ff;
            margin-right: 8px;
        }
        .title-name {
            font-weight: bold;
        }
        .button {
            margin-left: 24px;
        }
    }
    .tips:before {
        content: '*';
        color: #e50834;
        margin-right: 4px;
    }
}
.wti-form2-v2 ::v-deep {
    .el-input-group__append,
    .el-input-group__prepend {
        color: #44444f;
    }
}
</style>
